/*******************************************************************************
* @file    fins_doubly_linked_list.h
* @author  Fins
* @brief   
* @time    2020-11-17 19:21:17 Tuesday
* @codeing UTF-8
* @license
*     Copyright 2020 Fins
*
*     Licensed under the Apache License, Version 2.0 (the "License");
*     you may not use this file except in compliance with the License.
*     You may obtain a copy of the License at
*
*         http://www.apache.org/licenses/LICENSE-2.0
*
*     Unless required by applicable law or agreed to in writing, software
*     distributed under the License is distributed on an "AS IS" BASIS,
*     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*     See the License for the specific language governing permissions and
*     limitations under the License.
* @verbatim
================================================================================
                        ##### xxxxxxxxxxxxxxxxxxxxxxx #####
================================================================================
* @endverbatim
* @attention
*******************************************************************************/



/** Prevent recursive inclusion */
#ifndef __FINS_DOUBLY_LINKED_LIST_H
#define __FINS_DOUBLY_LINKED_LIST_H

/** C++ compatible */
#ifdef __cplusplus
 extern "C" {
#endif /** __cplusplus */

/* Includes start *************************************************************/
/*     Lib files ****************************** */

/*     User files ***************************** */
#include "fins_define.h"
#include "fins_struct.h"

/* Includes end ***************************************************************/

/* Exported define start ******************************************************/

/**
  * @brief Create a doubly linked list node and init
  * @param[in] name: Node name
  * @retval None
  */
#define FDLL_NEW_NODE(name)      fdll_douListN_s name ={&name,&name};

/**
  * @brief Get the structure entry where the linked list node is located
  * @param[in] listNode: Linked list node pointer
  * @param[in] typeName: Struct name where the linked list node is located
  * @param[in] memberName: The member name of the linked list node
  * @retval Struct entry point
  */
#define FDLL_GET_ENTRY_POINTER(listNodeP, typeName, memberName)                \
     FS_GET_ENTRY_POINTER(listNodeP,typeName,memberName)

/**
  * @brief Foreach doubly linked list
  * @param[out] tempNodeP: Temporary pointer,store current node
  * @param[in] listHeadP: List head pointer,waiting foreach
  * @retval None
  */
#define FDLL_FOREACH(tempNodeP, listHeadP)                                     \
    do{                                                                        \
        fdll_node_s* __##tempNodeP##Copy;                                      \
        for((tempNodeP) = (listHeadP)->next,                                   \
            __##tempNodeP##Copy = (tempNodeP)->next;                           \
            (tempNodeP) != (listHeadP);                                        \
            (tempNodeP) = __##tempNodeP##Copy,                                 \
            __##tempNodeP##Copy = (tempNodeP)->next)

/**
  * @brief Foreach the struct entry pointer where doubly linked list node is 
  *     located
  * @param[out] tempP: Temporary pointer,store current struct entry pointer
  * @param[in] listHeadP: List head pointer,waiting foreach
  * @retval Struct entry point
  */
#define FDLL_ENTRY_POINTER_FOREACH(tempP, listHeadP, memberName)               \
    do{                                                                        \
        typeof(tempP) __##tempNodeP##Copy;                                     \
        for(                                                                   \
            (tempP) = FDLL_GET_ENTRY_POINTER(                                  \
                (listHeadP)->next,                                             \
                typeof(*tempP),memberName),                                    \
            __##tempNodeP##Copy = FDLL_GET_ENTRY_POINTER(                      \
                (tempP)->memberName.next,                                      \
                typeof(*tempP),memberName);                                    \
                                                                               \
            &(tempP)->memberName != (listHeadP);                               \
                                                                               \
            (tempP) = __##tempNodeP##Copy,                                     \
            __##tempNodeP##Copy = FDLL_GET_ENTRY_POINTER(                      \
                (tempP)->memberName.next,                                      \
                typeof(*tempP),memberName)                                     \
        )

/**
  * @brief Must add at the end of doubly linked list foreach
  */
#define FDLL_FOREACH_END                                               }while(0)

/* Exported define end ********************************************************/

/* Exported typedef start *****************************************************/

/*************************************************
 * @brief Doubly linked list node define
 ************************************************/
typedef struct fdll_node
{
    struct fdll_node* prev;       /**< Previous node point. */
    struct fdll_node* next;       /**< Next node point. */
}fdll_node_s;




/* Exported typedef end *******************************************************/

/* Exported variable start ****************************************************/





/* Exported variable end ******************************************************/

/* Exported function start ****************************************************/

/**
  * @brief Doubly linked list initialize
  * @param[in] headNode: linked list head node
  * @retval None
  */
F_INLINE void FdllInit(fdll_node_s* headNode)
{
    headNode->prev = headNode;
    headNode->next = headNode;
}

/**
  * @brief Doubly linked list insert 'prev'->'new'->'next'
  * @param[in] new: New node
  * @param[in] prev: Previous node
  * @param[in] next: Next node
  * @retval None
  */
F_INLINE void __FdllInsert(
    fdll_node_s* newNode, 
    fdll_node_s* prevNode, 
    fdll_node_s* nextNode)
{
	nextNode->prev = newNode;
	newNode->next = nextNode;
	newNode->prev = prevNode;
	prevNode->next = newNode;
}

/**
  * @brief Doubly linked list insert forward 
  *     'otherNode'->'new'->'next'->'otherNode'
  * @param[in] new: New node
  * @param[in] next: Next node
  * @retval None
  */
F_INLINE void FdllInsertBefor(fdll_node_s* newNode, fdll_node_s* nextNode)
{
    __FdllInsert(newNode,nextNode->prev,nextNode);
}

/**
  * @brief Doubly linked list insert backward 
  *     'otherNode'->'Prev'->'new'->'otherNode'
  * @param[in] new: New node
  * @param[in] Prev: Previous node
  * @retval None
  */
F_INLINE void FdllInsertAfter(fdll_node_s* newNode, fdll_node_s* prevNode)
{
    __FdllInsert(newNode,prevNode,prevNode->next);
}

/**
  * @brief Insert at the head of doubly linked list
  * @param[in] new: New node
  * @param[in] Head: List Head
  * @retval None
  */
F_INLINE void FdllInsertHead(fdll_node_s* newNode, fdll_node_s* headNode)
{
    FdllInsertAfter(newNode,headNode);
}

/**
  * @brief Insert at the tail of doubly linked list
  * @param[in] new: New node
  * @param[in] Head: List Head
  * @retval None
  */
F_INLINE void FdllInsertTail(fdll_node_s* newNode, fdll_node_s* headNode)
{
    FdllInsertBefor(newNode,headNode);
}

/**
  * @brief Delet doubly linked list Node
  * @param[in] delNode: Node pointer,points to the node to be deleted
  * @retval None
  */
F_INLINE void FdllRemoveNode(fdll_node_s* delNode)
{
    delNode->prev->next = delNode->next;
    delNode->next->prev = delNode->prev;
    delNode->next = delNode->prev = delNode;
}


/**
  * @brief Judge is list empty
  * @param[in] listHead: Linked list head pointer
  * @retval Bool valve
  */
F_INLINE fbool FllIsEmpty(fdll_node_s* listHead)
{
    return listHead->next == listHead;
}


extern fuint32 FdllGetLen(fdll_node_s* listHead);

/* Exported function end ******************************************************/

/** C++ compatible */
#ifdef __cplusplus
}
#endif /** __cplusplus */

#endif /** __FINS_DOUBLY_LINKED_LIST_H */
////////////////////////////////- END OF FILE  -////////////////////////////////
